package demo

import (
	"fmt"
	"math/rand"
	"mit-6.824/src/labrpc"
	"sync/atomic"
	"time"
)

// 当前角色
const LEADER = "Leader"
const FOLLOWER = "Follower"
const CANDIDATES = "Candidates"
/**
每个节点
 */
type Node struct {
	peers     []*labrpc.ClientEnd // RPC end points of all peers
	nodeIdx        int                 // this peer's index into peers[]

	// 所有服务器，持久化状态（lab-2A不要求持久化）
	currentTerm       int        // 见过的最大任期
	votedFor          int        // 记录在currentTerm任期投票给谁了
	// 所有服务器，选举相关状态
	role              string    // 身份
	leaderIdx          int       // leader的id
	lastActiveTime    time.Time // 上次活跃时间（刷新时机：收到leader心跳、给其他candidates投票、请求其他节点投票）
	lastBroadcastTime time.Time // 作为leader，上次的广播时间

	// 仅Leader，易失状态（成为leader时重置）
	nextIndex  []int //	每个follower的log同步起点索引（初始为leader log的最后一项）
	matchIndex []int // 每个follower的log同步进度（初始为0），和nextIndex强关联

	lastIncludedIndex int        // snapshot最后1个logEntry的index，没有snapshot则为0
	lastIncludedTerm  int        // snapthost最后1个logEntry的term，没有snaphost则无意义
	log               []LogEntry // 操作日志

	dead      int32               // set by Kill()

	applyCh chan ApplyMsg // 应用层的提交队列
}

type RequestVoteArgs struct {
	// Your data here (2A, 2B).
	Term         int
	CandidateId  int
	LastLogIndex int
	LastLogTerm  int
}

type ApplyMsg struct {
	// 向application层提交日志
	Command      interface{}
	CommandIndex int
	CommandTerm  int

}

type RequestVoteReply struct {
	// Your data here (2A).
	Term        int
	VoteGranted bool
}

// 日志项
type LogEntry struct {
	Command interface{}
	Term    int
}



/**
  rpc list,
  当前节点idex
  竞选的通道
 */
func Init(peers []*labrpc.ClientEnd, me int, applyCh chan ApplyMsg) *Node {
	node:=&Node{}
	node.peers=peers
	node.nodeIdx=me
	node.role=FOLLOWER
	node.leaderIdx=-1
	node.votedFor=-1
	node.applyCh=applyCh

	//创建选举
	go node.electionLoop()

	return node
}

// 无期限循环
func (rf *Node) electionLoop() {
	for !rf.killed(){
		time.Sleep(10 * time.Millisecond)
		func(){
			now := time.Now()
			timeout := time.Duration(200+rand.Int31n(150)) * time.Millisecond // 超时随机化
			waitTime := now.Sub(rf.lastActiveTime)
			if(rf.role==FOLLOWER){
				if waitTime>=timeout{
					//为跟随者，且超一定时间没有心跳，或者投票
					rf.role=CANDIDATES
					fmt.Printf("[%v]follower-->candidates", rf.nodeIdx)
				}
			}
			//请求投票
			if rf.role==CANDIDATES && waitTime>=timeout {
				rf.lastActiveTime=now
				rf.currentTerm+=1
				rf.votedFor=rf.nodeIdx

				//构建拉票req
				args := RequestVoteArgs{
					Term:         rf.currentTerm,
					CandidateId:  rf.nodeIdx,
					LastLogIndex: rf.lastIndex(),
				}
				args.LastLogTerm = rf.lastTerm()

				type VoteResult struct {
					peerId int
					resp   *RequestVoteReply
				}
				voteCount := 1   // 收到投票个数（先给自己投1票）
				finishCount := 1 // 收到应答个数
				voteResultChan := make(chan *VoteResult, len(rf.peers))
				for peerId := 0; peerId < len(rf.peers); peerId++ {
					go func(id int) {
						if id == rf.nodeIdx {
							return
						}
						resp := RequestVoteReply{}
						if ok := rf.sendRequestVote(id, &args, &resp); ok {
							voteResultChan <- &VoteResult{peerId: id, resp: &resp}
						} else {
							voteResultChan <- &VoteResult{peerId: id, resp: nil}
						}
					}(peerId)
				}
				maxTerm := 0
				for {
					select {
					case voteResult := <-voteResultChan:
						finishCount += 1
						if voteResult.resp != nil {
							if voteResult.resp.VoteGranted {
								voteCount += 1
							}
							if voteResult.resp.Term > maxTerm {
								maxTerm = voteResult.resp.Term
							}
						}
						// 得到大多数vote后，立即离开
						if finishCount == len(rf.peers) || voteCount > len(rf.peers)/2 {
							goto VOTE_END
						}
					}
				}
			VOTE_END:
				//当领导者的最后核实。。
				defer func() {
					fmt.Printf("RaftNode[%d] RequestVote ends, finishCount[%d] voteCount[%d] Role[%s] maxTerm[%d] currentTerm[%d]", rf.nodeIdx, finishCount, voteCount,
						rf.role, maxTerm, rf.currentTerm)
				}()
				// 如果角色改变了，则忽略本轮投票结果
				if rf.role != CANDIDATES {
					return
				}
				// 发现了更高的任期，切回follower
				if maxTerm > rf.currentTerm {
					rf.role = FOLLOWER
					rf.leaderIdx = -1
					rf.currentTerm = maxTerm
					rf.votedFor = -1
					return
				}
				// 赢得大多数选票，则成为leader
				if voteCount > len(rf.peers)/2 {
					rf.role = LEADER
					rf.leaderIdx = rf.nodeIdx
					rf.nextIndex = make([]int, len(rf.peers))
					for i := 0; i < len(rf.peers); i++ {
						rf.nextIndex[i] = rf.lastIndex() + 1
					}
					rf.matchIndex = make([]int, len(rf.peers))
					for i := 0; i < len(rf.peers); i++ {
						rf.matchIndex[i] = 0
					}
					rf.lastBroadcastTime = time.Unix(0, 0) // 令appendEntries广播立即执行
					return
				}
			}
		}()
	}
}
func (rf *Node) RequestVote(args *RequestVoteArgs, reply *RequestVoteReply) {


	reply.Term = rf.currentTerm
	reply.VoteGranted = false

	fmt.Printf("RaftNode[%d] Handle RequestVote, CandidatesId[%d] Term[%d] CurrentTerm[%d] LastLogIndex[%d] LastLogTerm[%d] votedFor[%d]",
		rf.nodeIdx, args.CandidateId, args.Term, rf.currentTerm, args.LastLogIndex, args.LastLogTerm, rf.votedFor)
	defer func() {
		fmt.Printf("RaftNode[%d] Return RequestVote, CandidatesId[%d] Term[%d] currentTerm[%d] VoteGranted[%v] ", rf.nodeIdx, args.CandidateId,
			args.Term, rf.currentTerm, reply.VoteGranted)
	}()

	// 任期不如我大，拒绝投票
	if args.Term < rf.currentTerm {
		return
	}

	// 发现更大的任期，则转为该任期的follower
	if args.Term > rf.currentTerm {
		rf.currentTerm = args.Term
		rf.role = FOLLOWER
		rf.votedFor = -1
		rf.leaderIdx = -1
		// 继续向下走，进行投票
	}

	// 每个任期，只能投票给1人
	if rf.votedFor == -1 || rf.votedFor == args.CandidateId {
		// candidate的日志必须比我的新
		// 1, 最后一条log，任期大的更新
		// 2，任期相同, 更长的log则更新
		lastLogTerm := rf.lastTerm()
		// 这里坑了好久，一定要严格遵守论文的逻辑，另外log长度一样也是可以给对方投票的
		if args.LastLogTerm > lastLogTerm || (args.LastLogTerm == lastLogTerm && args.LastLogIndex >= rf.lastIndex()) {
			rf.votedFor = args.CandidateId
			reply.VoteGranted = true
			rf.lastActiveTime = time.Now() // 为其他人投票，那么重置自己的下次投票时间
		}
	}
}

// 最后的index
func (rf *Node) lastIndex() int {
	return rf.lastIncludedIndex + len(rf.log)
}

// 最后的term
func (rf *Node) lastTerm() (lastLogTerm int) {
	lastLogTerm = rf.lastIncludedTerm // for snapshot
	if len(rf.log) != 0 {
		lastLogTerm = rf.log[len(rf.log)-1].Term
	}
	return
}

func (rf *Node) sendRequestVote(server int, args *RequestVoteArgs, reply *RequestVoteReply) bool {
	ok := rf.peers[server].Call("Node.RequestVote", args, reply)
	return ok
}

func (rf *Node) Kill() {
	atomic.StoreInt32(&rf.dead, 1)
	// Your code here, if desired.
}

func (rf *Node) killed() bool {
	z := atomic.LoadInt32(&rf.dead)
	return z == 1
}


func (rf *Node) GetState() (int, bool) {


	var term int
	var isleader bool
	// Your code here (2A).
	term = rf.currentTerm
	isleader = rf.role == LEADER
	return term, isleader
}
